﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Kinect;
using Coding4Fun.Kinect;
using Microsoft.Speech.Recognition;
using Microsoft.Speech.AudioFormat;
using Microsoft.Speech;
using System.Windows;

namespace FGP_Kpaint
{
    class VoiceRecognition
    {
        private MainWindow main;
        private Controler controller;
        private KinectSensor _sensor;

        //voice
        private const string AcceptedSpeechPrefix = "Accepted_";
        private const string RejectedSpeechPrefix = "Rejected_";
        private SpeechRecognitionEngine speechRecognizer;
        
        private int index;

        public VoiceRecognition(KinectSensor sensor, MainWindow mains, Controler con)
        {
            this._sensor = sensor;
            this.main = mains;
            this.controller = con;

        }

        public void init_voicRecognition()
        {
            index = 9;
            this.speechRecognizer = this.createSpeechRecognizer();
            //audio
            var audioSource = this._sensor.AudioSource;
            audioSource.BeamAngleMode = BeamAngleMode.Adaptive;
        }

        public int getIndex() {
            return index;
        }

      /*  private static RecognizerInfo GetKinectRecognizer()
        {
            Func<RecognizerInfo, bool> matchingFunc = r =>
            {
                string value;
                r.AdditionalInfo.TryGetValue("Kinect", out value);
                return "True".Equals(value, StringComparison.InvariantCultureIgnoreCase) && "en-US".Equals(r.Culture.Name, StringComparison.InvariantCultureIgnoreCase);
            };
            return SpeechRecognitionEngine.InstalledRecognizers().Where(matchingFunc).FirstOrDefault();
        }*/

        private SpeechRecognitionEngine createSpeechRecognizer()
        {

            RecognizerInfo ri = getKinectRecognizer();
            if (ri == null)
            {
                MessageBox.Show("problem initializing speech engine");
                main.Close();
                return null;
            }

            SpeechRecognitionEngine sre = null;
            try
            {

                sre = new SpeechRecognitionEngine(ri.Id);
            }
            catch
            {
                MessageBox.Show("problem loading speech recognition engine");
                main.Close();
                return null;
            }

            var grammar = new Choices();
            grammar.Add("red");
            grammar.Add("blue");
            grammar.Add("green");
            grammar.Add("yellow");
            grammar.Add("brown");
            grammar.Add("white");
            grammar.Add("black");
            grammar.Add("up");
            grammar.Add("down");
            grammar.Add("hi");

            var gb = new GrammarBuilder { Culture = ri.Culture };
            gb.Append(grammar);

            //create the actual grammar instance and load it
            var g = new Grammar(gb);

            sre.LoadGrammar(g);

            //  DictationGrammar _dictationGrammar = new DictationGrammar();
            // sre.LoadGrammar(_dictationGrammar);
            //sre.RecognizeAsync(RecognizeMode.Multiple);


            sre.SpeechRecognized += new EventHandler<SpeechRecognizedEventArgs>(sre_SpeechRecognized);
            sre.SpeechHypothesized += new EventHandler<SpeechHypothesizedEventArgs>(sre_SpeechHypothesized);
            sre.SpeechRecognitionRejected += new EventHandler<SpeechRecognitionRejectedEventArgs>(sre_SpeechRecognitionRejected);

            return sre;
        }

        void sre_SpeechRecognitionRejected(object sender, SpeechRecognitionRejectedEventArgs e)
        {
            this.RejectSpeech(e.Result);
        }

        void sre_SpeechHypothesized(object sender, SpeechHypothesizedEventArgs e)
        {
            this.ReportSpeechStatus("Hypothesized: " + e.Result.Text + " " + e.Result.Confidence);
        }

        void sre_SpeechRecognized(object sender, SpeechRecognizedEventArgs e)
        {

            if (e.Result.Confidence < 0.5)
            {
                this.RejectSpeech(e.Result);
                return;
            }

            switch (e.Result.Text.ToUpperInvariant())
            {

                case "RED":
                    main.textBlock3.Text = "Accepted word : red";
                    index = 0;
                    break;

                case "BLUE":
                     main.textBlock3.Text = "Accepted word : blue";
                    index = 1;
                    break;

                case "GREEN":
                    main.textBlock3.Text = "Accepted word : green";
                    index = 2;
                    break;

                case "YELLOW":
                    main.textBlock3.Text = "Accepted word : yellow";
                    index = 3;
                    break;

                case "BROWN":
                    main.textBlock3.Text = "Accepted word : brown";
                    index = 4;
                    break;

                case "WHITE":
                    main.textBlock3.Text = "Accepted word : white";
                    index = 5;
                    break;

                case "BLACK":
                    main.textBlock3.Text = "Accepted word : black";
                    index = 6;
                    break;

                case "UP":
                    main.textBlock3.Text = "Accepted word : up";
                    index = 7;
                    break;

                case "DOWN":
                    main.textBlock3.Text = "Accepted word : down";
                    index = 8;
                    break;

                case "HI":
                    main.textBlock3.Text = "Accepted word : hi";
                    index = 9;
                    break;

                default:
                    break;
            }

            controller.brush.line2.Stroke = controller.array[index].line2.Stroke;
            controller.brush.size = controller.array[index].size;
            string status = "Recognized: " + e.Result.Text + " " + e.Result.Confidence;
            this.ReportSpeechStatus(status);
        }

        private RecognizerInfo getKinectRecognizer()
        {
            Func<RecognizerInfo, bool> matchingFunc = r =>
            {
                string value;
                r.AdditionalInfo.TryGetValue("Kinect", out value);
                return "True".Equals(value, StringComparison.InvariantCultureIgnoreCase) && "en-US".Equals(r.Culture.Name, StringComparison.InvariantCultureIgnoreCase);
            };

            return SpeechRecognitionEngine.InstalledRecognizers().Where(matchingFunc).FirstOrDefault();
        }



        private void RejectSpeech(RecognitionResult result)
        {
            string status = "Rejected: " + (result == null ? string.Empty : result.Text + " " + result.Confidence);
            this.ReportSpeechStatus(status);

            main.Dispatcher.BeginInvoke(new Action(() => { main.textBlock1.Text = "reject"; }));
        }

        private void ReportSpeechStatus(string status)
        {
           main.Dispatcher.BeginInvoke(new Action(() => { main.textBlock1.Text = status; }));
        }

        private void UpdateInstructionsText(string instructions)
        {
            main.Dispatcher.BeginInvoke(new Action(() => { main.textBlock1.Text = instructions; }));
        }


        //start
        public void start_voiceRecognition()
        {
            //set sensor audio source to variable
            var audioSource = _sensor.AudioSource;
            //Set the beam angle mode - the direction the audio beam is pointing
            //we want it to be set to adaptive
            audioSource.BeamAngleMode = BeamAngleMode.Adaptive;
            //start the audiosource 
            var kinectStream = audioSource.Start();
            //configure incoming audio stream
            speechRecognizer.SetInputToAudioStream(
                kinectStream, new SpeechAudioFormatInfo(EncodingFormat.Pcm, 16000, 16, 1, 32000, 2, null));
            //make sure the recognizer does not stop after completing     
            speechRecognizer.RecognizeAsync(RecognizeMode.Multiple);
            //reduce background and ambient noise for better accuracy
            _sensor.AudioSource.EchoCancellationMode = EchoCancellationMode.None;
            _sensor.AudioSource.AutomaticGainControlEnabled = false;
        }

        public void stop_voiceRecognition() {

            if (this.speechRecognizer != null && _sensor != null)
            {
                _sensor.AudioSource.Stop();
                this.speechRecognizer.RecognizeAsyncCancel();
                this.speechRecognizer.RecognizeAsyncStop();
            }
        }
    
    }
}
